/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * This file is part of retabel.
 *
 * Copyright (c) 2011 by individual contributors as indicated by the
 * @author tags. See the copyright.txt file in the distribution
 * for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.retabel.service.manager;

import org.retabel.persistence.dao.report.ReportDesignPackageDao;
import org.retabel.persistence.entity.report.RenderingEngineEnum;
import org.retabel.persistence.entity.report.ReportDesign;
import org.retabel.persistence.entity.report.ReportDesignPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * Service for managing report designs packages.
 * <p/>
 * <h3>Extra-Info</h3>
 * Created: 18:52 01.07.11
 *
 * @author Burt Parkers
 * @version 1.0
 */
@Stateless
public class ReportDesignPackageManagerBean implements ReportDesignPackageManager {

    /** The Logger. */
    private static final Logger logger = LoggerFactory.getLogger(ReportDesignPackageManagerBean.class);

    /** Dao to access the report designs. */
    @EJB
    private ReportDesignPackageDao reportDesignPackageDao;


    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public ReportDesignPackage[] findAllSorted(int from, int maxResults) {
        return reportDesignPackageDao.findAllSorted(from, maxResults);
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void store(RenderingEngineEnum renderingEngine, String name, String version, byte[] bytes) {
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream));
            ZipEntry entry;

            ReportDesignPackage reportDesignPackage = new ReportDesignPackage();
            reportDesignPackage.setRenderingEngine(renderingEngine);
            reportDesignPackage.setName(name);
            reportDesignPackage.setVersion(version);
            reportDesignPackage.setReportDesigns(new ArrayList<ReportDesign>());
            logger.debug("ReportDesignPackage: " + reportDesignPackage);

            while ((entry = zipInputStream.getNextEntry()) != null) {
                String entryName = entry.getName();
                if (!entry.isDirectory()) {
                    byte[] designContent = unzipEntry(zipInputStream);

                    logger.debug("Size of entry: " + entryName + ", " + designContent.length);

                    ReportDesign reportDesign = new ReportDesign();
                    reportDesign.setName(entryName);
                    reportDesign.setContent(designContent);
                    reportDesign.setReportDesignPackage(reportDesignPackage);

                    reportDesignPackage.getReportDesigns().add(reportDesign);
                }
            }

            if (reportDesignPackage.getReportDesigns().isEmpty()) {
                // ZipInputStream doesn't throw an exception if the byte stream isn't a real zip archive, therefore
                // throw a Exception if not at least one zip entry has been found

                throw new RuntimeException("achiveData contains not at least one zip entry!");
            }

            reportDesignPackageDao.create(reportDesignPackage);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public ReportDesignPackage findByNameAndVersion(String name, String version) {
        return reportDesignPackageDao.findByNameAndVersion(name, version);
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public int count() {
        return reportDesignPackageDao.count();
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void remove(String name, String version) {
        ReportDesignPackage reportDesignPackage = reportDesignPackageDao.findByNameAndVersion(name, version);

        if (reportDesignPackage != null)
        {
            reportDesignPackageDao.remove(reportDesignPackage);
        }
    }

    /**
     * Unzips an entry.
     *
     * @param zipInputStream the {@linkplain ZipInputStream}.
     * @return the uncompressed entry.
     * @throws IOException if an IO Error occurs.
     */
    private byte[] unzipEntry(ZipInputStream zipInputStream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int c = zipInputStream.read(); c != -1; c = zipInputStream.read()) {
            baos.write(c);
        }
        return baos.toByteArray();
    }

}
